﻿using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Web;

namespace Auros.Categorisation
{
    public static class PublishedContentExtensions
    {
        /// <summary>
        /// Gets the categories associated with the current content item.
        /// </summary>
        /// <param name="content">The current content.</param>
        /// <param name="propertyAlias">The alias of the property which is used for storing the associated category IDs.</param>
        /// <returns>Collection of category objects.</returns>
        public static IEnumerable<Category> GetCategories(this IPublishedContent content, string propertyAlias)
        {
            if (propertyAlias == null)
                throw new ArgumentNullException("propertyAlias");

            if (string.IsNullOrEmpty(propertyAlias))
                throw new ArgumentException("Input cannot be empty.", "propertyAlias");

            var property = content.GetProperty(propertyAlias);

            if (property != null && !string.IsNullOrEmpty(property.Value as string))
                return Categories.GetCategories(property.GetValueAsIntArray());
            else
                return new Category[0];
        }

        /// <summary>
        /// Determines whether the current content item has the specified category assigned to it.
        /// </summary>
        /// <param name="content">The current content item.</param>
        /// <param name="propertyAlias">The alias of the property which is used for storing the associated category IDs.</param>
        /// <param name="categoryId">The ID of the category which is to be checked.</param>
        /// <returns>
        /// <c>True</c> if the current content item has the specified category assigned; otherwise, <c>false</c>.
        /// </returns>
        public static bool HasCategoryAssigned(this IPublishedContent content, string propertyAlias, int categoryId)
        {
            if (content == null)
                throw new ArgumentNullException("content");

            if (propertyAlias == null)
                throw new ArgumentNullException("propertyAlias");

            if (string.IsNullOrEmpty(propertyAlias))
                throw new ArgumentException("Input cannot be empty.", "propertyAlias");

            var property = content.GetProperty(propertyAlias);

            if (property != null)
                return property.GetValueAsIntArray().Contains(categoryId);
            else
                return false;
        }

        /// <summary>
        /// Gets the child content items by category.
        /// </summary>
        /// <param name="content">The current content.</param>
        /// <param name="propertyAlias">The alias of the category property.</param>
        /// <param name="categoryId">The ID of the category.</param>
        /// <returns>Collection of child content items filtered by the given category ID.</returns>
        public static IEnumerable<IPublishedContent> GetChildrenByCategory(this IPublishedContent content, string propertyAlias, int categoryId)
        {
            return content.Children.Where(n => n.HasCategoryAssigned(propertyAlias, categoryId));
        }

        /// <summary>
        /// Gets the descendant content items by category.
        /// </summary>
        /// <param name="content">The current content.</param>
        /// <param name="propertyAlias">The alias of the category property.</param>
        /// <param name="categoryId">The ID of the category.</param>
        /// <returns>Collection of descendant content items filtered by the given category ID.</returns>
        public static IEnumerable<IPublishedContent> GetDescendantsByCategory(this IPublishedContent content, string propertyAlias, int categoryId)
        {
            return content.Descendants().Where(n => n.HasCategoryAssigned(propertyAlias, categoryId));
        }

        /// <summary>
        /// Gets the descendant content items by category.
        /// </summary>
        /// <param name="content">The current content.</param>
        /// <param name="propertyAlias">The alias of the category property.</param>
        /// <param name="categoryId">The ID of the category.</param>
        /// <param name="nodeTypeAlias">The node type alias.</param>
        /// <returns>Collection of descendant content items filtered by the given category ID and node type.</returns>
        public static IEnumerable<IPublishedContent> GetDescendantsByCategory(this IPublishedContent content, string propertyAlias, int categoryId, string nodeTypeAlias)
        {
            return content.Descendants(nodeTypeAlias).Where(n => n.HasCategoryAssigned(propertyAlias, categoryId));
        }
    }
}